﻿using Abp.Application.Services;
using Abp.Application.Services.Dto;
using Abp.Authorization;
using Abp.Domain.Repositories;
using Abp.EntityFrameworkCore.EFPlus;
using Abp.Events.Bus;
using Abp.Extensions;
using Abp.Linq.Extensions;
using Abp.UI;
using ARchGL.Platform.Authorization.Users;
using ARchGL.Platform.Core;
using ARchGL.Platform.Dtos;
using ARchGL.Platform.EventHandlers.Events;
using ARchGL.Platform.Juneng;
using ARchGL.Platform.Organizations;
using ARchGL.Platform.Organizations.Dto;
using ARchGL.Platform.Utils;
using Microsoft.EntityFrameworkCore;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace ARchGL.Platform.Application
{
    /// <summary>
    /// 公告 实现
    /// </summary>
    [AbpAuthorize]
    public class NoticesAppService : PlatformAppServiceBase, INoticesAppService
    {
        private readonly IRepository<Notices, Guid> noticesRepository;
        private readonly IRepository<NoticesUsers, Guid> noticesUsersRepository;
        private readonly IRepository<Projects, Guid> projectsRepository;
        private readonly IOrganizationUnitAppService organizationUnitAppService;
        private readonly IRepository<SelfChecks, Guid> selfChecksRepository;
        private readonly IRepository<SecurityChecks, Guid> securityChecksRepository;
        private readonly IRepository<SecurityCheckItems, Guid> securityCheckItemsRepository;
        public IEventBus EventBus { get; set; }

        public NoticesAppService(IRepository<Notices, Guid> _noticesRepository, IRepository<NoticesUsers, Guid> _noticesUserRepository,
            IRepository<Projects, Guid> _projectsRepository, IRepository<SecurityChecks, Guid> _securityChecksRepository,
            IRepository<SelfChecks, Guid> _selfChecksRepository, IRepository<SecurityCheckItems, Guid> _securityCheckItemsRepository,
            IOrganizationUnitAppService _organizationUnitAppService)
        {
            noticesRepository = _noticesRepository;
            noticesUsersRepository = _noticesUserRepository;
            projectsRepository = _projectsRepository;
            selfChecksRepository = _selfChecksRepository;
            securityChecksRepository = _securityChecksRepository;
            securityCheckItemsRepository = _securityCheckItemsRepository;
            organizationUnitAppService = _organizationUnitAppService;
            EventBus = NullEventBus.Instance;
        }

        /// <summary>
        /// 发布公告、新闻等消息（巡检、自检由系统自动发送）
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<Guid> Create(CreateNoticesInput input)
        {
            var entity = ObjectMapper.Map<Notices>(input);
            entity.CreatorUserId = UserManager.PrimaryId;
            await noticesRepository.InsertAsync(entity);
            var userList = new List<Guid>();

            if (input.IsAll)//推送所有用户
            {
                userList = UserManager.Users.Select(x => x.PrimaryId).ToList();
            }
            else if (input.OrganizationUnitId > 0)//获取当前部门下所有用户，并将公告分发
            {
                var organizationUnitUserList = await organizationUnitAppService.GetOrganizationUnitUsers(new GetOrganizationUnitUsersInput { Id = input.OrganizationUnitId });
                userList = organizationUnitUserList.Items.Select(x => x.UserPrimaryId).Distinct().ToList();
            }
            else if (input.OrganizationUnitIdList.Any()) //获取部门集合下的所有用户
            {
                var organizationUnitUserList = await organizationUnitAppService.GetOrganizationUnitUsers(input.OrganizationUnitIdList);
                userList = organizationUnitUserList.Select(x => x.UserPrimaryId).Distinct().ToList();
            }

            await EventBus.TriggerAsync(new SendNoticeEvent(entity.Id, userList, UserManager.PrimaryId));

            return entity.Id;
        }

        /// <summary>
        /// 修改公告 标题/内容
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task Modify(ModifyNoticesInput input)
        {
            var entity = await noticesRepository.FirstOrDefaultAsync(input.Id);
            if (entity == null) throw new UserFriendlyException(L("TheItemDoesNotExist"), L("PleaseRefreshThePageAndTryAgain"));
            entity.Title = input.Title.Trim();
            entity.Content = input.Content;
            await noticesRepository.UpdateAsync(entity);
        }

        /// <summary>
        /// 标记隐藏/显示，根据当前状态反转
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task MarkHideOrShow(Guid input)
        {
            var entity = await noticesRepository.FirstOrDefaultAsync(input);
            if (entity == null) throw new UserFriendlyException(L("TheItemDoesNotExist"), L("PleaseRefreshThePageAndTryAgain"));
            entity.Status = entity.Status == 1 ? 2 : 1;
            await noticesRepository.UpdateAsync(entity);
        }

        /// <summary>
        /// 批量删除公告
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task BatchRemove(List<Guid> input)
        {
            var list = await noticesRepository.GetAll().Where(x => input.Contains(x.Id)).ToListAsync();
            foreach (var item in list)
            {
                await noticesRepository.DeleteAsync(item);

                //回收已分发公告
                //var nuList = await noticesUsersRepository.GetAllListAsync(x => x.NoticeId == item.Id);
                //foreach (var nu in nuList)
                //{
                //    await noticesUsersRepository.DeleteAsync(nu);
                //}
                await noticesUsersRepository.BatchDeleteAsync(x => x.NoticeId == item.Id);
            }
        }

        /// <summary>
        /// 获取公告详情
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<NoticeDetailDto> QueryDetailById(Guid input)
        {
            var entity = await noticesRepository.FirstOrDefaultAsync(input);
            if (entity == null) throw new UserFriendlyException(L("TheItemDoesNotExist"), L("PleaseRefreshThePageAndTryAgain"));
            var result = ObjectMapper.Map<NoticeDetailDto>(entity);
            result.CreatorUserName = await UserManager.GetUserNameByIdAsync(entity.CreatorUserId);

            await MarkRead(await noticesUsersRepository.FirstOrDefaultAsync(x => x.NoticeId == entity.Id && x.UserId == UserManager.PrimaryId));

            return result;
        }

        /// <summary>
        /// 获取公告（管理员查看己发公告）-分页数据集合
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<NoticesDto>> QueryPagedList(QueryNoticesInput input)
        {
            var query = noticesRepository.GetAll()
                .Where(x => x.Type == 1)
                .WhereCreationTimeRange1(input.CreationTimeRange)
                .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.Title.Contains(input.Filter) || x.Content.Contains(input.Filter));

            var result = ObjectMapper.Map<List<NoticesDto>>(await query.OrderByDescending(x => x.CreationTime).PageByAsync(input));

            var userIdList = result.Select(x => x.CreatorUserId).Distinct().ToList();
            var userList = await UserManager.GetUserByIdListAsync(userIdList);
            foreach (var item in result)
            {
                item.CreatorUserName = userList.GetNameOrEmpty(item.CreatorUserId);
            }

            return new PagedResultDto<NoticesDto>(query.Count(), result);
        }

        /// <summary>
        /// 批量标记已读
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task BatchMarkRead(List<Guid> input)
        {
            //var list = await noticesUsersRepository.GetAll().Where(x => x.UserId == UserManager.UserId && input.Contains(x.NoticeId)).ToListAsync();
            //foreach (var item in list) await MarkRead(item);

            await noticesUsersRepository.BatchUpdateAsync(x => new NoticesUsers { Status = 1 }, x => x.UserId == UserManager.PrimaryId && input.Contains(x.NoticeId));
        }

        /// <summary>
        /// 标记全部已读（当前用户所有未读标记为已读）
        /// </summary>
        /// <returns></returns>
        public async Task MarkAllRead()
        {
            //var list = await noticesUsersRepository.GetAll().Where(x => x.UserId == UserManager.UserId && x.Status != 1).ToListAsync();
            //foreach (var item in list) await MarkRead(item);

            await noticesUsersRepository.BatchUpdateAsync(x => new NoticesUsers { Status = 1 }, x => x.UserId == UserManager.PrimaryId && x.Status != 1);
        }

        /// <summary>
        /// 批量删除自己的公告
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task BatchRemoveByCurrentUser(List<Guid> input)
        {
            //var list = await noticesUsersRepository.GetAll().Where(x => x.UserId == UserManager.UserId && input.Contains(x.NoticeId)).ToListAsync();
            //foreach (var item in list) await noticesUsersRepository.DeleteAsync(item);

            await noticesUsersRepository.BatchDeleteAsync(x => x.UserId == UserManager.PrimaryId && input.Contains(x.NoticeId));
        }

        /// <summary>
        /// 获取最新公告（自定义条数）
        /// </summary>
        /// <param name="input">返回行数</param>
        /// <returns></returns>
        public async Task<dynamic> QueryTopList(int input)
        {
            var query = from n in noticesRepository.GetAll()
                        join nu in noticesUsersRepository.GetAll() on n.Id equals nu.NoticeId into nuJoined
                        from nu in nuJoined.DefaultIfEmpty()
                        orderby n.CreationTime descending
                        where nu.UserId == UserManager.PrimaryId && n.Status == 1//只筛选显示的消息
                        select new
                        {
                            n.Id,
                            n.PrimaryId,
                            n.Title,
                            n.Content,
                            n.Type,
                            nu.Status,
                            n.CreationTime
                        };
            return await query.Take(input).ToListAsync();
        }

        /// <summary>
        /// 获取自己的公告通知等消息-分页数据集合
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        public async Task<PagedResultDto<NoticesDto>> QueryMyPagedList(QueryNoticesInput input)
        {
            var query = from n in noticesRepository.GetAll()
                        join nu in noticesUsersRepository.GetAll() on n.Id equals nu.NoticeId into nuJoined
                        from nu in nuJoined.DefaultIfEmpty()
                        join u in UserManager.Users on nu.UserId equals u.PrimaryId into uJoined
                        from u in uJoined.DefaultIfEmpty()
                        where nu.UserId == UserManager.PrimaryId && n.Status == 1//只筛选显示的消息
                                                                                 //&& (input.Status > 0 && (nu.Status == input.Status))
                                                                                 //&& (!input.Filter.IsNullOrWhiteSpace() && (n.Title.Contains(input.Filter) || n.Content.Contains(input.Filter)))
                        select new
                        {
                            n.Id,
                            n.PrimaryId,
                            n.Title,
                            n.Content,
                            n.Type,
                            nu.Status,
                            CreatorUserName = u.Name,
                            n.CreationTime
                        };

            query = query
                .WhereIf(input.Status > 0, x => x.Status == input.Status)
                //.WhereCreationTimeRange(input.CreationTimeRange)
                .WhereIf(!input.Filter.IsNullOrWhiteSpace(), x => x.Title.Contains(input.Filter) || x.Content.Contains(input.Filter));

            var result = await query.OrderByDescending(x => x.CreationTime).PageByAsync(input);

            var list = new List<NoticesDto>();
            foreach (var item in result)
            {
                list.Add(new NoticesDto
                {
                    Id = item.Id,
                    PrimaryId = item.PrimaryId,
                    Title = item.Title,
                    Type = item.Type,
                    Status = item.Status,
                    CreatorUserName = item.CreatorUserName,
                    CreationTime = item.CreationTime,
                });
            }

            return new PagedResultDto<NoticesDto>(query.Count(), list);
        }

        /// <summary>
        /// 获取自己的公告概况
        /// </summary>
        /// <returns></returns>
        public async Task<int> QueryMyOverview()
        {
            var query = from n in noticesRepository.GetAll()
                        join nu in noticesUsersRepository.GetAll() on n.Id equals nu.NoticeId into nuJoined
                        from nu in nuJoined.DefaultIfEmpty()
                        where nu.UserId == UserManager.PrimaryId && n.Status == 1//只筛选显示的消息
                        && nu.Status == 2//只统计未读
                        select new { n.Type };

            return await query.CountAsync();
        }

        #region RemoteService

        /// <summary>
        /// 发送巡检通知
        /// </summary>
        /// <param name="input">巡检</param>
        /// <returns></returns>
        [RemoteService(false)]
        public async Task SendNotice(SecurityChecksInput input)
        {
            //if (input.Status == EnumCheckAndFeedbackStatus.整改中) return;
            var entity = new Notices
            {
                PrimaryId = input.Id,
                Title = $"[{securityCheckItemsRepository.GetNameOrEmpty(input.CheckItemId)}]{projectsRepository.GetNameOrEmpty(input.ProjectId)}",
#if !DEBUG
                Content = UserManager.UserName + "的检查事件已通知给你",
#else
                Content = "admin的检查事件已通知给你",
#endif
                Type = 3,
                Status = 1,
                CreatorUserId = UserManager.PrimaryId
            };
            await noticesRepository.InsertAsync(entity);
            await noticesUsersRepository.InsertAsync(entity.Id, UserManager.PrimaryId, input.CheckUsersArray, input.NotifyUsersArray, input.CCUsersArray);

#if !DEBUG
            await SendToMe(entity, "你的检查事件已通知" + string.Join(" ", await UserManager.GetUserNameListByIdListAsync(input.CheckUsersArray, input.NotifyUsersArray, input.CCUsersArray)));
#endif
        }

        /// <summary>
        /// 发送 整改回复/复查意见 通知
        /// </summary>
        /// <param name="input">整改与回复</param>
        /// <returns></returns>
        [RemoteService(false)]
        public async Task SendNotice(SecurityCheckAndFeedbacksInput input)
        {
            var securityCheck = await securityChecksRepository.FirstOrDefaultAsync(input.CheckId);
            if (securityCheck == null) throw new UserFriendlyException(L("TheItemDoesNotExist"), L("PleaseRefreshThePageAndTryAgain"));
            var type = input.Type == EnumCheckFeedbackType.整改回复 ? "整改" : "复查";
            var checkUsersArray = ((JArray)JsonConvert.DeserializeObject(securityCheck.CheckUsersArray)).Values().Select(c => Guid.Parse(c.ToString())).ToList();
            var entity = new Notices
            {
                PrimaryId = input.CheckId,
                Title = $"[{securityCheckItemsRepository.GetNameOrEmpty(securityCheck.CheckItemId)}]{projectsRepository.GetNameOrEmpty(securityCheck.ProjectId)}",
#if !DEBUG
                Content = UserManager.UserName + $"已对你做出{type}回复{(input.Status == EnumCheckAndFeedbackStatus.已完成 ? "并通过" : "")}",
#else
                Content = $"已对你做出{type}回复{(input.Status == EnumCheckAndFeedbackStatus.已完成 ? "并通过" : "")}",
#endif
                Type = 3,
                Status = 1,
                CreatorUserId = UserManager.PrimaryId
            };

            //根据 type 判断发送通知人，尽量减少影响范围
            await noticesRepository.InsertAsync(entity);
            var userIdList = checkUsersArray;
            if (input.Type == EnumCheckFeedbackType.整改回复)//回复通知检查人
                await noticesUsersRepository.InsertAsync(entity.Id, UserManager.PrimaryId, checkUsersArray); //, input.NotifyUsersArray, input.CCUsersArray
            else //复查通知 通知人/整改人            
            {
                userIdList = JsonConvert.DeserializeObject<List<Guid>>(input.NotifyUsersArray);
                await noticesUsersRepository.InsertAsync(entity.Id, UserManager.PrimaryId, userIdList);
            }

            await SendToMe(entity, "你的整改回复已通知" + string.Join(" ", await UserManager.GetUserNameListByIdListAsync(userIdList)));
        }

        /// <summary>
        /// 发送移交巡检通知
        /// </summary>
        /// <param name="input">移交</param>
        /// <returns></returns>
        [RemoteService(false)]
        public async Task SendNotice(TurnOverCheckInput input)
        {
            var securityCheck = await securityChecksRepository.FirstOrDefaultAsync(input.CheckId);
            if (securityCheck == null) throw new UserFriendlyException(L("TheItemDoesNotExist"), L("PleaseRefreshThePageAndTryAgain"));
            var entity = new Notices
            {
                PrimaryId = input.CheckId,
                Title = $"[{securityCheckItemsRepository.GetNameOrEmpty(securityCheck.CheckItemId)}]{projectsRepository.GetNameOrEmpty(securityCheck.ProjectId)}",
#if !DEBUG
                Content = UserManager.UserName + "的检查事件已移交给你",
#else
                Content = "的检查事件已移交给你",
#endif
                Type = 3,
                Status = 1,
                CreatorUserId = UserManager.PrimaryId
            };
            await noticesRepository.InsertAsync(entity);
            await noticesUsersRepository.InsertAsync(entity.Id, UserManager.PrimaryId, input.NotifyUsersArray);

            var list = ((JArray)JsonConvert.DeserializeObject(securityCheck.CCUsersArray)).Values().Select(c => Guid.Parse(c.ToString())).ToList();
            await SendToMe(entity, "你的检查事件已移交" + string.Join(" ", await UserManager.GetUserNameListByIdListAsync(input.NotifyUsersArray, list)));
        }

        /// <summary>
        /// 发送撤销巡检通知
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [RemoteService(false)]
        public async Task SendNotice(SecurityCheckDto input)
        {
            var entity = new Notices
            {
                PrimaryId = input.Id,
                Title = $"[{securityCheckItemsRepository.GetNameOrEmpty(input.CheckItemId)}]{projectsRepository.GetNameOrEmpty(input.ProjectId)}",
#if !DEBUG
                Content = UserManager.UserName + "的检查事件已撤销",
#else
                Content = "的检查事件已撤销",
#endif
                Type = 3,
                Status = 1,
                CreatorUserId = UserManager.PrimaryId
            };
            var usersArray = entity.GetUserIdList(input.NotifyUsersArray, input.CCUsersArray, input.CheckUsersArray);
            await noticesRepository.InsertAsync(entity);
            await noticesUsersRepository.InsertAsync(entity.Id, UserManager.PrimaryId, usersArray);

            await SendToMe(entity, "你的检查事件已撤销");
        }

        /// <summary>
        /// 发送自检通知
        /// </summary>
        /// <param name="input">自检</param>
        /// <returns></returns>
        [RemoteService(false)]
        public async Task SendNotice(SelfChecksInput input)
        {
            //if (input.Status == EnumSelfCheckStatus.已整改) return;
            var entity = new Notices
            {
                PrimaryId = input.Id,
                Title = $"[自检]{input.Content}",
                Content = "检查事件已通知" + string.Join(" ", await UserManager.GetUserNameListByIdListAsync(input.NotifyUsersArray, input.CCUsersArray)),
                Type = 4,
                Status = 1,
                CreatorUserId = UserManager.PrimaryId
            };
            await noticesRepository.InsertAsync(entity);
            await noticesUsersRepository.InsertAsync(entity.Id, UserManager.PrimaryId, input.CheckUsersArray, input.NotifyUsersArray, input.CCUsersArray);
        }

        /// <summary>
        /// 发送撤销自检通知
        /// </summary>
        /// <param name="input"></param>
        /// <returns></returns>
        [RemoteService(false)]
        public async Task SendNotice(SelfChecksDto input)
        {
            var entity = new Notices
            {
                PrimaryId = input.Id,
                Title = $"[自检]{input.Content}",
#if !DEBUG
                Content = UserManager.UserName + "的检查事件已撤销",
#else
                Content = "的检查事件已撤销",
#endif
                Type = 4,
                Status = 1,
                CreatorUserId = UserManager.PrimaryId
            };
            var usersArray = entity.GetUserIdList(input.NotifyUsersArray, input.CCUsersArray, input.CheckUsersArray);
            await noticesRepository.InsertAsync(entity);
            await noticesUsersRepository.InsertAsync(entity.Id, UserManager.PrimaryId, usersArray);
        }

        #region Private method

        //给自己发通知
        private async Task SendToMe(Notices notice, string content)
        {
            var entity = new Notices
            {
                PrimaryId = notice.PrimaryId,
                Title = notice.Title,
                Content = content,
                Type = 2,
                Status = notice.Status,
                CreatorUserId = notice.CreatorUserId
            };
            var id = await noticesRepository.InsertAndGetIdAsync(entity);
            await noticesUsersRepository.InsertAsync(id, UserManager.PrimaryId.Value, UserManager.PrimaryId.Value, 1);
        }

        #endregion

        #endregion

        #region Private method

        private async Task MarkRead(NoticesUsers noticesUser)
        {
            if (noticesUser == null) return;
            noticesUser.Status = 1; //标记已读
            await noticesUsersRepository.UpdateAsync(noticesUser);
        }

        #endregion
    }
}
